diff options
| author | Fuwn <[email protected]> | 2026-01-24 13:09:50 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-01-24 13:09:50 +0000 |
| commit | 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch) | |
| tree | b9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/app/(main)/websites/[websiteId]/events/EventProperties.tsx | |
| download | umami-main.tar.xz umami-main.zip | |
Created from https://vercel.com/new
Diffstat (limited to 'src/app/(main)/websites/[websiteId]/events/EventProperties.tsx')
| -rw-r--r-- | src/app/(main)/websites/[websiteId]/events/EventProperties.tsx | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx new file mode 100644 index 0000000..c3b1325 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx @@ -0,0 +1,127 @@ +import { Column, Grid, ListItem, Select } from '@umami/react-zen'; +import { useMemo, useState } from 'react'; +import { PieChart } from '@/components/charts/PieChart'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { + useEventDataPropertiesQuery, + useEventDataValuesQuery, + useMessages, +} from '@/components/hooks'; +import { ListTable } from '@/components/metrics/ListTable'; +import { CHART_COLORS } from '@/lib/constants'; + +export function EventProperties({ websiteId }: { websiteId: string }) { + const [propertyName, setPropertyName] = useState(''); + const [eventName, setEventName] = useState(''); + + const { formatMessage, labels } = useMessages(); + const { data, isLoading, isFetching, error } = useEventDataPropertiesQuery(websiteId); + + const events: string[] = data + ? data.reduce((arr: string | any[], e: { eventName: any }) => { + return !arr.includes(e.eventName) ? arr.concat(e.eventName) : arr; + }, []) + : []; + const properties: string[] = eventName + ? data?.filter(e => e.eventName === eventName).map(e => e.propertyName) + : []; + + return ( + <LoadingPanel + data={data} + isLoading={isLoading} + isFetching={isFetching} + error={error} + minHeight="300px" + > + <Column gap="6"> + {data && ( + <Grid columns="repeat(auto-fill, minmax(300px, 1fr))" marginBottom="3" gap> + <Select + label={formatMessage(labels.event)} + value={eventName} + onChange={setEventName} + placeholder="" + > + {events?.map(p => ( + <ListItem key={p} id={p}> + {p} + </ListItem> + ))} + </Select> + <Select + label={formatMessage(labels.property)} + value={propertyName} + onChange={setPropertyName} + isDisabled={!eventName} + placeholder="" + > + {properties?.map(p => ( + <ListItem key={p} id={p}> + {p} + </ListItem> + ))} + </Select> + </Grid> + )} + {eventName && propertyName && ( + <EventValues websiteId={websiteId} eventName={eventName} propertyName={propertyName} /> + )} + </Column> + </LoadingPanel> + ); +} + +const EventValues = ({ websiteId, eventName, propertyName }) => { + const { + data: values, + isLoading, + isFetching, + error, + } = useEventDataValuesQuery(websiteId, eventName, propertyName); + + const propertySum = useMemo(() => { + return values?.reduce((sum, { total }) => sum + total, 0) ?? 0; + }, [values]); + + const chartData = useMemo(() => { + if (!propertyName || !values) return null; + return { + labels: values.map(({ value }) => value), + datasets: [ + { + data: values.map(({ total }) => total), + backgroundColor: CHART_COLORS, + borderWidth: 0, + }, + ], + }; + }, [propertyName, values]); + + const tableData = useMemo(() => { + if (!propertyName || !values || propertySum === 0) return []; + return values.map(({ value, total }) => ({ + label: value, + count: total, + percent: 100 * (total / propertySum), + })); + }, [propertyName, values, propertySum]); + + return ( + <LoadingPanel + isLoading={isLoading} + isFetching={isFetching} + data={values} + error={error} + minHeight="300px" + gap="6" + > + {values && ( + <Grid columns="1fr 1fr" gap> + <ListTable title={propertyName} data={tableData} /> + <PieChart type="doughnut" chartData={chartData} /> + </Grid> + )} + </LoadingPanel> + ); +}; |